package com.tencent.liteav.demo.superplayer.ui.player

import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.ProgressBar
import android.widget.RelativeLayout
import android.widget.TextView
import com.bumptech.glide.Glide
import com.tencent.liteav.demo.superplayer.R
import com.tencent.liteav.demo.superplayer.SuperPlayerDef
import com.tencent.liteav.demo.superplayer.SuperPlayerDef.PlayerState
import com.tencent.liteav.demo.superplayer.SuperPlayerModel
import com.tencent.liteav.demo.superplayer.helper.PictureInPictureHelper
import com.tencent.liteav.demo.superplayer.model.entity.PlayImageSpriteInfo
import com.tencent.liteav.demo.superplayer.model.entity.PlayKeyFrameDescInfo
import com.tencent.liteav.demo.superplayer.model.entity.VideoQuality
import com.tencent.liteav.demo.superplayer.model.utils.VideoGestureDetector
import com.tencent.liteav.demo.superplayer.model.utils.VideoGestureDetector.VideoGestureListener
import com.tencent.liteav.demo.superplayer.model.utils.VideoQualityUtils
import com.tencent.liteav.demo.superplayer.ui.view.PointSeekBar
import com.tencent.liteav.demo.superplayer.ui.view.PointSeekBar.OnSeekBarPointClickListener
import com.tencent.liteav.demo.superplayer.ui.view.PointSeekBar.PointParams
import com.tencent.liteav.demo.superplayer.ui.view.VideoProgressLayout
import com.tencent.liteav.demo.superplayer.ui.view.VodMoreView
import com.tencent.liteav.demo.superplayer.ui.view.VodResolutionView
import com.tencent.liteav.demo.superplayer.ui.view.VodResolutionView.OnClickResolutionItemListener
import com.tencent.liteav.demo.superplayer.ui.view.VodSoundTrackView
import com.tencent.liteav.demo.superplayer.ui.view.VodSoundTrackView.OnClickSoundTrackItemListener
import com.tencent.liteav.demo.superplayer.ui.view.VodSubtitlesSettingView
import com.tencent.liteav.demo.superplayer.ui.view.VodSubtitlesSettingView.OnClickBackButtonListener
import com.tencent.liteav.demo.superplayer.ui.view.VodSubtitlesView
import com.tencent.liteav.demo.superplayer.ui.view.VodSubtitlesView.OnClickSettingListener
import com.tencent.liteav.demo.superplayer.ui.view.VodSubtitlesView.OnClickSubtitlesItemListener
import com.tencent.liteav.demo.superplayer.ui.view.VolumeBrightnessProgressLayout
import com.tencent.liteav.demo.superplayer.ui.view.download.DownloadMenuListView
import com.tencent.liteav.txcplayer.model.TXSubtitleRenderModel
import com.tencent.rtmp.TXImageSprite
import com.tencent.rtmp.TXTrackInfo

open class BasicPlayer @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0,
) : AbsPlayer(context, attrs, defStyle), View.OnClickListener, VodMoreView.Callback,
    OnClickResolutionItemListener, PointSeekBar.OnSeekBarChangeListener,
    OnSeekBarPointClickListener, OnClickSoundTrackItemListener,
    OnClickSubtitlesItemListener, OnClickSettingListener, OnClickBackButtonListener {
    @JvmField
    protected var mLayoutTop: RelativeLayout? = null
    @JvmField
    protected var mLayoutBottom: LinearLayout? = null
    @JvmField
    protected var mTvTitle: TextView? = null
    @JvmField
    protected var mIvRewind: ImageView? = null
    @JvmField
    protected var mIvForward: ImageView? = null
    @JvmField
    protected var mIvFullScreenOn: ImageView? = null
    @JvmField
    protected var mIvFullScreenOff: ImageView? = null
    @JvmField
    protected var mIvFloatIn: ImageView? = null
    @JvmField
    protected var mIvFloatExit: ImageView? = null
    @JvmField
    protected var mIvFullBack: ImageView? = null
    @JvmField
    protected var mIvWindowBack: ImageView? = null
    @JvmField
    protected var mIvPiP: ImageView? = null
    @JvmField
    protected var mIvSnapshot: ImageView? = null
    @JvmField
    protected var mIvPlayNext: ImageView? = null
    @JvmField
    protected var isShowing: Boolean = false
    @JvmField
    protected var mCurrentPlayState: PlayerState = PlayerState.END
    @JvmField
    protected var mPlayType: SuperPlayerDef.PlayerType? = null
    @JvmField
    protected var mIvPause: ImageView? = null
    @JvmField
    protected var mPbLiveLoading: ProgressBar? = null
    @JvmField
    protected var mSeekBarProgress: PointSeekBar? = null
    @JvmField
    protected var mTvBackToLive: TextView? = null
    @JvmField
    protected var isDestroy: Boolean = false
    @JvmField
    protected var mGestureVolumeBrightnessProgressLayout: VolumeBrightnessProgressLayout? = null
    @JvmField
    protected var mGestureVideoProgressLayout: VideoProgressLayout? = null
    @JvmField
    protected var mIvPlayForward: RelativeLayout? = null
    @JvmField
    protected var mIvPlayBackward: RelativeLayout? = null
    @JvmField
    protected var mTvCurrent: TextView? = null
    @JvmField
    protected var mProgress: Long = 0
    @JvmField
    protected var mDuration: Long = 0
    @JvmField
    protected var mTvDuration: TextView? = null
    @JvmField
    protected var mVodMoreView: VodMoreView? = null
    @JvmField
    protected var mIvSoundTrack: ImageView? = null
    @JvmField
    protected var mIvSubtitle: ImageView? = null
    @JvmField
    protected var mTvQuality: TextView? = null
    @JvmField
    protected var mIvDanmu: ImageView? = null
    @JvmField
    protected var mIvDownload: ImageView? = null
    @JvmField
    protected var mIvMore: ImageView? = null
    @JvmField
    protected var mImageCover: ImageView? = null
    @JvmField
    protected var mVodResolutionView: VodResolutionView? = null
    @JvmField
    protected var mTvVttText: TextView? = null
    @JvmField
    protected var mDownloadMenuView: DownloadMenuListView? = null
    @JvmField
    protected var mIsChangingSeekBarProgress = false
    @JvmField
    protected var mLivePushDuration: Long = 0
    @JvmField
    protected var mBarrageOn = false
    @JvmField
    protected var mSelectedPos = -1
    @JvmField
    protected var mFirstShowQuality = false
    @JvmField
    protected var mVodSoundTrackView: VodSoundTrackView? = null
    @JvmField
    protected var mVodSubtitlesView: VodSubtitlesView? = null
    @JvmField
    protected var mVodSubtitlesSettingView: VodSubtitlesSettingView? = null
    @JvmField
    protected var mDefaultVideoQuality: VideoQuality? = null
    @JvmField
    protected var mTXImageSprite: TXImageSprite? = null
    @JvmField
    protected var mTXPlayKeyFrameDescInfoList: MutableList<PlayKeyFrameDescInfo> = arrayListOf()
    @JvmField
    protected var mVideoQualityList: MutableList<VideoQuality> = arrayListOf()

    private lateinit var mGestureDetector: GestureDetector
    private lateinit var mVideoGestureDetector: VideoGestureDetector
    private lateinit var mVideoGestureListener: VideoGestureListener

    init {
        initViews()
        findViews()
        initGesture()
    }

    private fun initViews(){
        LayoutInflater.from(context).inflate(getLayoutId(), this)
    }

    open fun findViews() {
        mIvRewind = findViewById(R.id.superplayer_iv_rewind)
        mIvRewind?.setOnClickListener(this)
        mIvForward = findViewById(R.id.superplayer_iv_fast_forward)
        mIvForward?.setOnClickListener(this)
        mIvFullScreenOn = findViewById(R.id.superplayer_iv_fullscreen_on)
        mIvFullScreenOn?.setOnClickListener(this)
        mIvFullScreenOff = findViewById(R.id.superplayer_iv_fullscreen_off)
        mIvFullScreenOff?.setOnClickListener(this)
        mIvFloatIn = findViewById(R.id.superplayer_iv_float_in)
        mIvFloatIn?.setOnClickListener(this)
        mIvFloatExit = findViewById(R.id.superplayer_iv_float_exit)
        mIvFloatExit?.setOnClickListener(this)
        mIvFullBack = findViewById(R.id.superplayer_iv_full_back)
        mIvFullBack?.setOnClickListener(this)
        mIvWindowBack = findViewById(R.id.superplayer_iv_window_back)
        mIvWindowBack?.setOnClickListener(this)
        mIvPiP = findViewById(R.id.superplayer_iv_pip)
        mIvPiP?.let { pip->
            pip.visibility = if (PictureInPictureHelper.hasPipPermission(context as Activity)) VISIBLE else GONE
            pip.setOnClickListener(this)
        }
        mIvSnapshot = findViewById(R.id.superplayer_iv_snapshot)
        mIvSnapshot?.setOnClickListener(this)
        mIvPlayNext = findViewById(R.id.superplayer_iv_play_next)
        mIvPlayNext?.setOnClickListener(this)
        mIvPause = findViewById(R.id.superplayer_iv_pause)
        mIvPause?.setOnClickListener(this)
        mTvBackToLive = findViewById(R.id.superplayer_tv_back_to_live)
        mTvBackToLive?.setOnClickListener(this)

        mPbLiveLoading = findViewById(R.id.superplayer_pb_live)
        mSeekBarProgress = findViewById(R.id.superplayer_seekbar_progress)
        mSeekBarProgress?.let { seekbar->
            seekbar.progress = 0
            seekbar.setOnPointClickListener(this)
            seekbar.setOnSeekBarChangeListener(this)
        }

        mGestureVolumeBrightnessProgressLayout = findViewById(R.id.superplayer_gesture_progress)
        mGestureVideoProgressLayout = findViewById(R.id.superplayer_video_progress_layout)

        mIvPlayForward = findViewById(R.id.superplayer_play_forward)
        mIvPlayBackward = findViewById(R.id.superplayer_play_backward)

        mLayoutTop = findViewById(R.id.superplayer_rl_top)
        mLayoutBottom = findViewById(R.id.superplayer_ll_bottom)
        mTvTitle = findViewById(R.id.superplayer_tv_title)
        mTvCurrent = findViewById(R.id.superplayer_tv_current)

        mTvDuration = findViewById(R.id.superplayer_tv_duration)
        mVodMoreView = findViewById(R.id.superplayer_vod_more)
        mVodMoreView?.setCallback(this)

        mIvDanmu = findViewById(R.id.superplayer_iv_danmuku)
        mIvDanmu?.setOnClickListener(this)

        mIvMore = findViewById(R.id.superplayer_iv_more)
        mIvMore?.setOnClickListener(this)

        mIvDownload = findViewById(R.id.superplayer_iv_download)
        mIvDownload?.setOnClickListener(this)

        mImageCover = findViewById(R.id.superplayer_cover_view)

        mIvSoundTrack = findViewById(R.id.superplayer_iv_sound_track)
        mIvSoundTrack?.setOnClickListener(this)

        mIvSubtitle = findViewById(R.id.superplayer_iv_subtitle)
        mIvSubtitle?.setOnClickListener(this)

        mVodSoundTrackView = findViewById(R.id.superplayer_vod_selection_sound_track)
        mVodSoundTrackView?.setOnClickSoundTrackItemListener(this)

        mVodSubtitlesView = findViewById(R.id.superplayer_vod_selection_subtitle)
        mVodSubtitlesView?.let { subtitlesView->
            subtitlesView.setOnClickSubtitlesItemListener(this)
            subtitlesView.setOnClickSettingListener(this)
        }

        mVodSubtitlesSettingView = findViewById(R.id.superplayer_vod_selection_subtitle_setting)
        mVodSubtitlesSettingView?.setOnClickBackButtonListener(this)

        mDownloadMenuView = findViewById(R.id.superplayer_cml_cache_menu)

        mTvQuality = findViewById(R.id.superplayer_tv_quality)
        mTvQuality?.let { tvQuality->
            tvQuality.setOnClickListener(this)
            tvQuality.text = mDefaultVideoQuality?.title?:context.getString(R.string.superplayer_original_picture)
        }

        mVodResolutionView = findViewById(R.id.superplayer_vod_resolution)
        mVodResolutionView?.setOnClickResolutionItemListener(this)

        mTvVttText = findViewById(R.id.superplayer_large_tv_vtt_text)
        mTvVttText?.setOnClickListener(this)
    }

    private fun initGesture(){
        mVideoGestureDetector = VideoGestureDetector(context)
        mVideoGestureListener = object : VideoGestureListener{
            override fun onBrightnessGesture(newBrightness: Float) {
                mGestureVolumeBrightnessProgressLayout?.let { volumeBrightness ->
                    val brightness = (newBrightness * 100).toInt()
                    volumeBrightness.setProgress(brightness)
                    volumeBrightness.setImageResource(R.drawable.superplayer_ic_light_max)
                    volumeBrightness.show()
                    mVodMoreView?.setBrightProgress(brightness)
                }
            }

            override fun onVolumeGesture(volumeProgress: Float) {
                mGestureVolumeBrightnessProgressLayout?.let { volumeBrightness ->
                    volumeBrightness.setProgress(volumeProgress.toInt())
                    volumeBrightness.setImageResource(R.drawable.superplayer_ic_volume_max)
                    volumeBrightness.show()
                }
            }

            override fun onSeekGesture(seekProgress: Int) {
                mIsChangingSeekBarProgress = true
                val progress = if (seekProgress > (mSeekBarProgress?.max ?: 100)) {
                    mSeekBarProgress?.max ?: 100
                } else if (seekProgress < 0) {
                    0
                } else {
                    seekProgress
                }
                mGestureVideoProgressLayout?.setProgress(progress)
                mGestureVideoProgressLayout?.show()

                setThumbnail(progress)

                mSeekBarProgress?.progress = progress

                val percentage = (progress.toFloat()) / (mSeekBarProgress?.max?:100)
                var currentTime = (mDuration * percentage)
                if (mPlayType == SuperPlayerDef.PlayerType.LIVE || mPlayType == SuperPlayerDef.PlayerType.LIVE_SHIFT) {
                    currentTime = if (mLivePushDuration > MAX_SHIFT_TIME) {
                        (mLivePushDuration - MAX_SHIFT_TIME * (1 - percentage)).toInt().toFloat()
                    } else {
                        mLivePushDuration * percentage
                    }
                    mGestureVideoProgressLayout?.setTimeText(formattedTime(currentTime.toLong()))
                } else {
                    mGestureVideoProgressLayout?.setTimeText(formattedTime(currentTime.toLong()) + " / " + formattedTime(mDuration))
                }
            }

        }
        mVideoGestureDetector.setVideoGestureListener(mVideoGestureListener)

        mGestureDetector = GestureDetector(
            context, object : GestureDetector.SimpleOnGestureListener() {
                override fun onDoubleTap(e: MotionEvent?): Boolean {
                    togglePlayState()
                    show()
                    hideViewDelay()
                    return true
                }

                override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
                    toggle()
                    return true
                }

                override fun onScroll(
                    downEvent: MotionEvent?,
                    moveEvent: MotionEvent?,
                    distanceX: Float,
                    distanceY: Float,
                ): Boolean {
                    if (downEvent == null || moveEvent == null) {
                        return false
                    }
                    mVideoGestureDetector.check(100,downEvent, moveEvent, distanceX, distanceY)
                    return true
                }

                override fun onDown(e: MotionEvent?): Boolean {
                    mVideoGestureDetector.reset(width, mSeekBarProgress?.progress ?: 0)
                    return true
                }

                override fun onLongPress(e: MotionEvent?) {
                    val x = e?.x ?: .0f
                    if (enableFingerTapFastPlay()) {
                        if (x < screenWidth / 4) {
                            mControllerCallback?.onPlayBackward()
                            mIvPlayForward?.visibility = GONE
                            mIvPlayBackward?.visibility = VISIBLE
                        } else if (x > screenWidth * 3 / 4) {
                            mControllerCallback?.onPlayForward()
                            mIvPlayForward?.visibility = VISIBLE
                            mIvPlayBackward?.visibility = GONE
                        }
                    }
                }
            },
            Handler(Looper.getMainLooper())
        )

        mGestureDetector.setIsLongpressEnabled(true)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (enableGesture()) {
            mGestureDetector.onTouchEvent(event)
        }

        val isCall = event.action == MotionEvent.ACTION_CANCEL || event.action == MotionEvent.ACTION_UP
        if (isCall && mVideoGestureDetector.isVideoProgressModel) {
            var progress = mVideoGestureDetector.videoProgress
            if (progress > (mSeekBarProgress?.max ?: 100)) {
                progress = mSeekBarProgress?.max?:100
            }
            if (progress < 0) {
                progress = 0
            }
            mSeekBarProgress?.progress = progress

            val percentage = progress * 1.0f / (mSeekBarProgress?.max?:100)
            val seekTime = if (mPlayType == SuperPlayerDef.PlayerType.LIVE || mPlayType == SuperPlayerDef.PlayerType.LIVE_SHIFT) {
                    if (mLivePushDuration > MAX_SHIFT_TIME) {
                        (mLivePushDuration - MAX_SHIFT_TIME * (1 - percentage)).toInt()
                    } else {
                        (mLivePushDuration * percentage).toInt()
                    }
                } else {
                    (percentage * mDuration).toInt()
                }
            mControllerCallback?.onSeekTo(seekTime)
            mIsChangingSeekBarProgress = false
        }

        if (event.action == MotionEvent.ACTION_DOWN) {
            removeHideViewTask()
        } else if (event.action == MotionEvent.ACTION_UP) {
            if (enableFingerTapFastPlay()){
                mControllerCallback?.onActionUp()
                mIvPlayForward?.visibility = GONE
                mIvPlayBackward?.visibility = GONE
            }
            hideViewDelay()
        }
        return true
    }

    override fun onClick(view: View) {
        when (view.id) {
            R.id.superplayer_iv_rewind -> {
                mControllerCallback?.onActionRewind()
            }
            R.id.superplayer_iv_fast_forward -> {
                mControllerCallback?.onActionForward()
            }
            R.id.superplayer_iv_fullscreen_on -> {
                mControllerCallback?.onSwitchPlayMode(SuperPlayerDef.PlayerMode.FULLSCREEN)
            }
            R.id.superplayer_iv_fullscreen_off -> {
                mControllerCallback?.onSwitchPlayMode(SuperPlayerDef.PlayerMode.WINDOW)
            }
            R.id.superplayer_iv_float_in -> {
                mControllerCallback?.onSwitchPlayMode(SuperPlayerDef.PlayerMode.FLOAT)
            }
            R.id.superplayer_iv_float_exit -> {
                mControllerCallback?.onBackPressed(SuperPlayerDef.PlayerMode.FLOAT)
            }
            R.id.superplayer_iv_full_back -> {
                mControllerCallback?.onBackPressed(SuperPlayerDef.PlayerMode.FULLSCREEN)
            }
            R.id.superplayer_iv_window_back -> {
                mControllerCallback?.onBackPressed(SuperPlayerDef.PlayerMode.WINDOW)
            }
            R.id.superplayer_iv_pip -> {
                mControllerCallback?.enterPictureInPictureMode()
            }
            R.id.superplayer_iv_snapshot -> {
                mControllerCallback?.onSnapshot()
            }
            R.id.superplayer_iv_play_next -> {
                mControllerCallback?.playNext()
            }
            R.id.superplayer_iv_pause -> {
                togglePlayState()
            }
            R.id.superplayer_tv_back_to_live -> {
                mControllerCallback?.onResumeLive()
            }
            R.id.superplayer_iv_danmuku -> {
                toggleBarrage()
            }
            R.id.superplayer_iv_more -> {
                showMoreView()
            }
            R.id.superplayer_tv_quality -> {
                showQualityView()
            }
            R.id.superplayer_large_tv_vtt_text -> {
                seekToKeyFramePos()
            }
            R.id.superplayer_iv_download -> {
                showCacheList()
            }
            R.id.superplayer_iv_sound_track -> {
                showSoundTrackView()
            }
            R.id.superplayer_iv_subtitle -> {
                showSubTitleView()
            }
        }
    }

    override fun onSpeedChange(speedLevel: Float) {
        mControllerCallback?.onSpeedChange(speedLevel)
    }

    override fun onMirrorChange(isMirror: Boolean) {
        mControllerCallback?.onMirrorToggle(isMirror)
    }

    override fun onHWAcceleration(isAccelerate: Boolean) {
        mControllerCallback?.onHWAccelerationToggle(isAccelerate)
    }

    override fun onClickResolutionItem(videoQuality: VideoQuality) {
        mControllerCallback?.onQualityChange(videoQuality)
        mVodResolutionView?.visibility = GONE
    }

    override fun onClickSoundTrackItem(clickInfo: TXTrackInfo) {
        mVodSoundTrackView?.visibility = GONE
        mControllerCallback?.onClickSoundTrackItem(clickInfo)
        hide()
    }

    override fun onClickBackButton() {
        mVodSubtitlesView?.visibility = VISIBLE
        mVodSubtitlesSettingView?.visibility = GONE
    }

    override fun onCLickDoneButton(model: TXSubtitleRenderModel) {
        mControllerCallback?.onClickSubtitleViewDoneButton(model)
        onClickBackButton()
    }

    override fun onClickSetting() {
        mVodSubtitlesView?.visibility = GONE
        mVodSubtitlesSettingView?.visibility = VISIBLE
    }

    override fun onClickSubtitlesItem(clickInfo: TXTrackInfo) {
        mVodSubtitlesView?.visibility = GONE
        mControllerCallback?.onClickSubtitleItem(clickInfo)
        hide()
    }

///////////////////////////////////////////////////////////////////////////////////////////////////
    fun togglePlayState() {
        when (mCurrentPlayState) {
            PlayerState.INIT, PlayerState.PAUSE, PlayerState.END -> mControllerCallback?.onResume()

            PlayerState.PLAYING, PlayerState.LOADING -> mControllerCallback?.onPause()
        }
        show()
    }

    open fun toggle() {
        if (isShowing) {
            hide()
        } else {
            show()
            hideViewDelay()
        }
        mVodMoreView?.visibility = GONE
        mVodSoundTrackView?.visibility = GONE
        mVodSubtitlesView?.visibility = GONE
        mVodSubtitlesSettingView?.visibility = GONE
    }

    fun preparePlayVideo(superPlayerModel: SuperPlayerModel){
        updateTitle(superPlayerModel.title)
        val coverPictureUrl = if(!TextUtils.isEmpty(superPlayerModel.coverPictureUrl)) superPlayerModel.coverPictureUrl
        else superPlayerModel.placeholderImage
        mImageCover?.let { cover->
            Glide.with(context).load(coverPictureUrl).placeholder(R.drawable.superplayer_default).into(cover)
        }
        mLivePushDuration = 0
        toggleView(mImageCover, true)
        mIvPause?.setImageResource(playIconRes())
        updateVideoProgress(0L, superPlayerModel.duration.toLong(),0L)
        mSeekBarProgress?.isEnabled = (superPlayerModel.playAction != SuperPlayerModel.PLAY_ACTION_MANUAL_PLAY)
        if (superPlayerModel.playAction == SuperPlayerModel.PLAY_ACTION_AUTO_PLAY) {
            toggleView(mPbLiveLoading, true)
        } else {
            toggleView(mPbLiveLoading, false)
        }
    }

    override fun show() {
        isShowing = true
        mLayoutTop?.visibility = VISIBLE
        mLayoutBottom?.visibility = VISIBLE
        val pointParams: MutableList<PointParams> = ArrayList()
        for (info in mTXPlayKeyFrameDescInfoList) {
            val progress = (info.time / mDuration * (mSeekBarProgress?.max?:100)).toInt()
            pointParams.add(PointParams(progress, Color.WHITE))
        }
        mSeekBarProgress?.setPointList(pointParams)
        if (mPlayType == SuperPlayerDef.PlayerType.LIVE_SHIFT) {
            if (mLayoutBottom?.visibility == VISIBLE) mTvBackToLive?.visibility = VISIBLE
        }
    }

    override fun hide() {
        isShowing = false
        mLayoutTop?.visibility = GONE
        mLayoutBottom?.visibility = GONE
        mVodResolutionView?.visibility = GONE
        mTvVttText?.visibility = GONE
        if (mPlayType == SuperPlayerDef.PlayerType.LIVE_SHIFT) {
            mTvBackToLive?.visibility = GONE
        }
    }

    override fun release() {
        isDestroy = true
        releaseTXImageSprite()
    }

    override fun updatePlayState(playState: PlayerState) {
        mCurrentPlayState = playState
        when (playState) {
            PlayerState.INIT -> mIvPause?.setImageResource(playIconRes())
            PlayerState.PLAYING -> {
                mSeekBarProgress?.isEnabled = true
                mIvPause?.setImageResource(pauseIconRes())
                toggleView(mPbLiveLoading, false)
            }

            PlayerState.LOADING -> {
                mSeekBarProgress?.isEnabled = true
                mIvPause?.setImageResource(pauseIconRes())
                toggleView(mPbLiveLoading, true)
            }

            PlayerState.PAUSE -> {
                mIvPause?.setImageResource(playIconRes())
                toggleView(mPbLiveLoading, false)
            }

            PlayerState.END -> {
                mIvPause?.setImageResource(playIconRes())
                toggleView(mPbLiveLoading, false)
            }
        }
    }

    override fun setVideoQualityList(list: MutableList<VideoQuality>?) {
        mVideoQualityList = list?: arrayListOf()
        mFirstShowQuality = false
    }

    override fun updateTitle(title: String?) {
        mTvTitle?.text = title
    }

    override fun updateVideoProgress(current: Long, duration: Long, playable: Long) {
        mProgress = if (current < 0) 0 else current
        mDuration = if (duration < 0) 0 else duration
        mTvCurrent?.text = formattedTime(mProgress)
        mTvDuration?.text = formattedTime(mDuration)

        var percentage = if (mDuration == 0L) {
            0f
        } else if (mDuration < 0) {
            1f
        } else {
            mProgress / mDuration.toFloat()
        }

        if (mPlayType == SuperPlayerDef.PlayerType.LIVE || mPlayType == SuperPlayerDef.PlayerType.LIVE_SHIFT) {
            mLivePushDuration = if (mLivePushDuration > mProgress) mLivePushDuration else mProgress
            val leftTime = mDuration - mProgress
            mDuration = if (mDuration > MAX_SHIFT_TIME) MAX_SHIFT_TIME.toLong() else mDuration
            percentage = 1 - leftTime.toFloat() / mDuration.toFloat()
        }

        if (percentage in 0.0..1.0) {
            val progress = Math.round(percentage * (mSeekBarProgress?.max?:100))
            if (!mIsChangingSeekBarProgress) {
                if (mPlayType == SuperPlayerDef.PlayerType.LIVE) {
                    mSeekBarProgress?.progress = 100
                } else {
                    mSeekBarProgress?.progress = progress
                }
            }
        }

        val playAblePercentage = if (playable == 0L){
            0f
        }else if (playable < 0){
            1f
        }else{
            playable / mDuration.toFloat()
        }

        if (playAblePercentage in 0.0..1.0){
            val progress = Math.round(playAblePercentage * (mSeekBarProgress?.max?:100))
            if (!mIsChangingSeekBarProgress){
                if (mPlayType == SuperPlayerDef.PlayerType.VOD) {
                    mSeekBarProgress?.setSecondaryProgress(progress)
                } else {
                    mSeekBarProgress?.setSecondaryProgress(100)
                }
            }
        }
    }

    override fun updatePlayType(type: SuperPlayerDef.PlayerType) {
        mPlayType = type
        when (type) {
            SuperPlayerDef.PlayerType.VOD -> {
                mTvBackToLive?.visibility = GONE
                mVodMoreView?.updatePlayType(SuperPlayerDef.PlayerType.VOD)
                mTvDuration?.visibility = VISIBLE
            }

            SuperPlayerDef.PlayerType.LIVE -> {
                mTvBackToLive?.visibility = GONE
                mTvDuration?.visibility = GONE
                mVodMoreView?.updatePlayType(SuperPlayerDef.PlayerType.LIVE)
                mSeekBarProgress?.progress = 100
            }

            SuperPlayerDef.PlayerType.LIVE_SHIFT -> {
                if (mLayoutBottom?.visibility == VISIBLE) {
                    mTvBackToLive?.visibility = VISIBLE
                }
                mTvDuration?.visibility = GONE
                mVodMoreView?.updatePlayType(SuperPlayerDef.PlayerType.LIVE_SHIFT)
            }
        }
    }

    override fun updateVideoQuality(videoQuality: VideoQuality?) {
        mDefaultVideoQuality = videoQuality
        mTvQuality?.text = VideoQualityUtils.transformToQualityName(videoQuality?.title)
        if (mVideoQualityList.isNotEmpty()) {
            for (i in mVideoQualityList.indices) {
                val quality = mVideoQualityList[i]
                if (quality.title != null && quality.title == mDefaultVideoQuality?.title) {
                    mVodResolutionView?.setCurrentPosition(i)
                    break
                }
            }
        }
    }

    override fun updateImageSpriteInfo(info: PlayImageSpriteInfo?) {
        releaseTXImageSprite()
        mGestureVideoProgressLayout?.setProgressVisibility(info?.imageUrls?.isEmpty() ?: true)
        if (mPlayType == SuperPlayerDef.PlayerType.VOD) {
            mTXImageSprite = TXImageSprite(context)
            if (info != null) {
                mTXImageSprite!!.setVTTUrlAndImageUrls(info.webVttUrl, info.imageUrls)
            } else {
                mTXImageSprite!!.setVTTUrlAndImageUrls(null, null)
            }
        }
    }

    override fun updateKeyFrameDescInfo(list: MutableList<PlayKeyFrameDescInfo>?) {
        mTXPlayKeyFrameDescInfoList = list ?: arrayListOf()
    }

    override fun setVideoQualityVisible(isShow: Boolean) {
        mTvQuality?.visibility = if (isShow) VISIBLE else GONE
    }

    override fun onProgressChanged(seekBar: PointSeekBar, progress: Int, fromUser: Boolean) {
        if (fromUser){
            mGestureVideoProgressLayout?.show()
            val percentage = (progress.toFloat()) / seekBar.max
            var currentTime = (mDuration * percentage)
            if (mPlayType == SuperPlayerDef.PlayerType.LIVE || mPlayType == SuperPlayerDef.PlayerType.LIVE_SHIFT) {
                currentTime = if (mLivePushDuration > MAX_SHIFT_TIME) {
                    (mLivePushDuration - MAX_SHIFT_TIME * (1 - percentage)).toInt().toFloat()
                } else {
                    mLivePushDuration * percentage
                }
                mGestureVideoProgressLayout?.setTimeText(formattedTime(currentTime.toLong()))
            } else {
                mGestureVideoProgressLayout?.setTimeText(formattedTime(currentTime.toLong()) + " / " + formattedTime(mDuration))
                setThumbnail(progress)
            }
            mGestureVideoProgressLayout?.setProgress(progress)
        }
    }

    override fun onStopTrackingTouch(seekBar: PointSeekBar) {
        val curProgress = seekBar.progress
        val maxProgress = seekBar.max
        when (mPlayType) {
            SuperPlayerDef.PlayerType.VOD -> if (curProgress in 0..maxProgress) {
                val percentage = (curProgress.toFloat()) / maxProgress
                val position = (mDuration * percentage).toInt()
                mControllerCallback?.onSeekTo(position)
            }

            SuperPlayerDef.PlayerType.LIVE, SuperPlayerDef.PlayerType.LIVE_SHIFT -> {
                toggleView(mPbLiveLoading, true)
                var seekTime = (mLivePushDuration * curProgress * 1.0f / maxProgress).toInt()
                if (mLivePushDuration > MAX_SHIFT_TIME) {
                    seekTime = (mLivePushDuration - MAX_SHIFT_TIME * (maxProgress - curProgress) * 1.0f / maxProgress).toInt()
                }
                mControllerCallback?.onSeekTo(seekTime)
            }
            else -> {}
        }
        hideViewDelay()
    }

    override fun onStartTrackingTouch(seekBar: PointSeekBar) {
        removeHideViewTask()
    }

    override fun onSeekBarPointClick(view: View, pos: Int) {
        hideViewDelay()
        mSelectedPos = pos
        view.post {
            val location = IntArray(2)
            view.getLocationInWindow(location)

            val viewX = location[0]
            val info = mTXPlayKeyFrameDescInfoList[pos]
            val content = info.content

            mTvVttText?.text = formattedTime(info.time.toLong()) + " " + content
            mTvVttText?.visibility = VISIBLE
            adjustVttTextViewPos(viewX)
        }
    }

    fun releaseTXImageSprite() {
        mTXImageSprite?.release()
        mTXImageSprite = null
    }

    fun showSoundTrackView() {
        hide()
        mVodSoundTrackView?.visibility = VISIBLE
    }

    fun showSubTitleView() {
        hide()
        mVodSubtitlesView?.visibility = VISIBLE
    }

    fun showCacheList() {
        val superPlayerModelList: List<SuperPlayerModel> = mControllerCallback?.playList?: arrayListOf()
        mDownloadMenuView?.let { downloadMenuListView ->
            downloadMenuListView.initDownloadData(
                superPlayerModelList,
                mVideoQualityList,
                mDefaultVideoQuality,
                "default"
            )
            downloadMenuListView.setCurrentPlayVideo(mControllerCallback.playingVideoModel)
            downloadMenuListView.setOnCacheListClick {
                mControllerCallback?.onShowDownloadList()
            }
            downloadMenuListView.show()
        }
    }

    fun toggleBarrage() {
        mBarrageOn = !mBarrageOn
        if (mBarrageOn) {
            mIvDanmu?.setImageResource(R.drawable.superplayer_ic_danmuku_on)
        } else {
            mIvDanmu?.setImageResource(R.drawable.superplayer_ic_danmuku_off)
        }
        mControllerCallback?.onDanmuToggle(mBarrageOn)
    }

    fun toggleCoverView(isVisible: Boolean) {
        toggleView(mImageCover, isVisible)
    }

    fun prepareLoading() {
        toggleView(mPbLiveLoading, true)
    }

    fun revertUI() {
        if (mBarrageOn) {
            mBarrageOn = false
            mIvDanmu?.setImageResource(R.drawable.superplayer_ic_danmuku_off)
        }
        mVodMoreView?.revertUI()
    }

    fun showMoreView() {
        hide()
        mVodMoreView?.visibility = VISIBLE
    }

    fun showQualityView() {
        if (mVideoQualityList.isEmpty()){
            return
        }
        if (mVideoQualityList.size == 1 && TextUtils.isEmpty(mVideoQualityList[0].title)){
            return
        }
        // Set the default display resolution text
        mVodResolutionView?.visibility = VISIBLE
        if (!mFirstShowQuality && mDefaultVideoQuality != null) {
            for (i in mVideoQualityList.indices) {
                val quality = mVideoQualityList[i]
                if (quality.title != null && quality.title == mDefaultVideoQuality?.title) {
                    mVodResolutionView?.setCurrentPosition(i)
                    break
                }
            }
            mFirstShowQuality = true
        }
        mVodResolutionView?.setModelList(mVideoQualityList)
    }

    fun seekToKeyFramePos(){
        val time = if (mSelectedPos < mTXPlayKeyFrameDescInfoList.size) mTXPlayKeyFrameDescInfoList[mSelectedPos].time else 0f
        mControllerCallback?.let { callback ->
            callback.onSeekTo(time.toInt())
            callback.onResume()
        }
        mTvVttText?.visibility = GONE
    }

    fun setThumbnail(progress: Int) {
        val percentage = (progress.toFloat()) / (mSeekBarProgress?.max?:100)
        val seekTime = (mDuration * percentage)
        val bitmap = mTXImageSprite?.getThumbnail(seekTime)
        if (bitmap != null) {
            mGestureVideoProgressLayout?.setThumbnail(bitmap)
        }
    }

    fun adjustVttTextViewPos(viewX: Int) {
        mTvVttText?.post {
            val width = mTvVttText!!.width
            val marginLeft = viewX - width / 2

            val params = mTvVttText!!.layoutParams as LayoutParams
            params.leftMargin = marginLeft

            if (marginLeft < 0) {
                params.leftMargin = 0
            }

            val screenWidth = getScreenWidth()
            if (marginLeft + width > screenWidth) {
                params.leftMargin = screenWidth - width
            }
            mTvVttText!!.layoutParams = params
        }
    }

    fun updateDownloadViewShow(isShow: Boolean) {
        if (isShow) {
            mIvDownload?.visibility = VISIBLE
        } else {
            mIvDownload?.visibility = GONE
        }
        mDownloadMenuView?.dismiss()
    }

    fun setVodSelectionViewPositionAndData(models: List<TXTrackInfo>, lastSelected: TXTrackInfo?) {
        mVodSoundTrackView?.setModelList(models)
        mVodSoundTrackView?.doInitAudioTrackSelect(lastSelected)
        mIvSoundTrack?.visibility = if (models.isEmpty()) GONE else VISIBLE
    }

    fun setVodSubtitlesViewPositionAndData(models: List<TXTrackInfo>) {
        mVodSubtitlesView?.setModelList(models)
        mIvSubtitle?.visibility = if (models.isEmpty()) GONE else VISIBLE
    }

    fun checkIsNeedRefreshCacheMenu() {
        if (mDownloadMenuView?.isShowing == true) {
            mDownloadMenuView?.notifyRefreshCacheState()
        }
    }

    fun setPlayNextButtonVisibility(isShowing: Boolean) {
        toggleView(mIvPlayNext, isShowing)
    }

    fun onVolumeChange(volume: Int) {
        mVideoGestureListener.onVolumeGesture(volume.toFloat() / (mVideoGestureDetector.maxVolume) * 100)
    }

    open fun pauseIconRes(): Int {
        return R.drawable.superplayer_ic_vod_pause_normal
    }

    open fun playIconRes(): Int {
        return R.drawable.superplayer_ic_vod_play_normal
    }

    open fun getLayoutId():Int{
        return R.layout.superplayer_vod_player_basic
    }

    open fun enableFingerTapFastPlay():Boolean{
        return true
    }

    open fun enableGesture():Boolean{
        return true
    }
}
